package com.wpw.java8demo;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import org.junit.Before;
import org.junit.Test;

public class CollectGroupTest {
	
	List<Apple> appList;
	String[] colors = {"red","green","yellow"};
	
	@Before
	public void before() {	
		appList = new ArrayList<>();
		Apple app;
		for (int i = 0; i < 20; i++) {
			app = new Apple();
			app.setColor(colors[i%3]);
			app.setWeigth(new Random().nextInt(10));
			appList.add(app);
		}
	}
	
	/**
	 * 分组
	 * @Description：
	 * @author: wupengwei
	 * @date: 2018年7月4日 下午9:41:32
	 */
	@Test
	public void test1() {
		Map<Object, List<Apple>> map = appList.stream()
			.collect(Collectors.groupingBy((a) -> {
				if (a.getWeigth() >= 0 && a.getWeigth() < 5) {
					return "low";
				} else if (a.getWeigth() == 5) {
					return "middle";
				} else {
					return "high";
				}
			}));
		map.keySet().stream()
			.forEach((key) -> {
				System.out.println(key + ":");
				List<Apple> list = map.get(key);
				list.forEach(System.out::print);
				System.out.println();
			});
	}
	
	/**
	 * 多级分组
	 * @Description：
	 * @author: wupengwei
	 * @date: 2018年7月4日 下午9:41:42
	 */
	@Test
	public void test2() {
		Map<String, Map<String, List<Apple>>> map = appList.stream()
			.collect(Collectors.groupingBy(Apple::getColor, Collectors.groupingBy((a) -> {
				if (a.getWeigth() >= 0 && a.getWeigth() < 5) {
					return "low";
				} else if (a.getWeigth() == 5) {
					return "middle";
				} else {
					return "high";
				}
			})));

		for (String color : map.keySet()) {
			System.out.println(color);
			Map<String, List<Apple>> map2 = map.get(color);
			System.out.println(map2);
			
		}
	}
	
	/**
	 * 按照子组手机数据
	 * @Description：
	 * @author: wupengwei
	 * @date: 2018年7月4日 下午9:41:50
	 */
	@Test
	public void test3() {
		Map<String, Long> map = appList.stream()
			.collect(Collectors.groupingBy(
					Apple::getColor, Collectors.counting()));
		System.out.println(map);
	}

	@Test
	public void test4() {
		Map<String, Optional<Apple>> maxMap = appList.stream()
			.collect(Collectors.groupingBy(Apple::getColor, Collectors.maxBy(Comparator.comparingInt(Apple::getWeigth))));
		System.out.println(maxMap);
		Map<String, Optional<Apple>> maxMap2 = appList.stream()
			.collect(Collectors.groupingBy(Apple::getColor, Collectors.maxBy((a,b) -> a.getWeigth().compareTo(b.getWeigth()))));
		System.out.println(maxMap2);
		System.out.println(maxMap.equals(maxMap2));
		
	}
	
	//收集器结果转化为另一种类型
	@Test
	public void test5() {
		Map<String, Apple> collect = appList.stream()
			.collect(Collectors.groupingBy(Apple::getColor, 
					Collectors.collectingAndThen(
							Collectors.maxBy(Comparator.comparingInt(Apple::getWeigth)), Optional<Apple>::get)));
		System.out.println(collect);
	}

	@Test
	public void test51() {
		Map<String, List<Apple>> collect = appList.stream().collect(Collectors.groupingBy(Apple::getColor));
		Map<String, List<Integer>> collect1 = appList.stream().collect(Collectors.groupingBy(
				Apple::getColor,
				Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().map(Apple::getWeigth).collect(Collectors.toList()))));
		System.out.println(collect1);

		Map<String, List<Integer>> collect2 =
				appList.stream().collect(Collectors.groupingBy(Apple::getColor, Collectors.mapping(Apple::getWeigth, Collectors.toList())));
		System.out.println(collect2);

	}
	
	
	@Test
	public void test6() {
		Map<String, Set<String>> appColorMap = appList.stream()
			.collect(Collectors.groupingBy(Apple::getColor,Collectors.mapping(
					(a) -> {
						if (a.getWeigth() >= 0 && a.getWeigth() < 5) {
							return "low";
						} else if (a.getWeigth() == 5) {
							return "middle";
						} else {
							return "high";
						}
					}, Collectors.toSet())));
		System.out.println(appColorMap);
	}
	
	//分区(true,false两组)
	@Test
	public void teset7() {
		Map<Boolean, List<Apple>> collect = appList.stream()
			.collect(Collectors.partitioningBy((a) -> {
				if (a.getWeigth() < 5) {
					return true;
				}
				return false;
			}));
		System.out.println(collect);
	}
	
	@Test
	public void test8() {
		Map<Boolean, Map<String, List<Apple>>> collect = appList.stream()
				.collect(Collectors.partitioningBy((a) -> {
					if (a.getWeigth() < 5) {
						return true;
					}
					return false;
				}, Collectors.groupingBy(Apple::getColor)));
		for (Boolean b : collect.keySet()) {
			System.out.println(b);
			System.out.println(collect.get(b));
		}

	}

	@Test
	public void test9() {
		List<Apple> apples = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			Apple apple = new Apple();
			apple.setWeigth(i);
			apple.setColor("");
			apples.add(apple);
		}

		Map<Integer, Apple> collect = apples.stream().collect(Collectors.toMap(Apple::getWeigth, apple -> apple));
		Map<Integer, String> collect1 = apples.stream().collect(Collectors.toMap(Apple::getWeigth, apple -> apple.getColor()));
		System.out.println(collect);

	}

	@Test
	public void test10() {
		List<Apple> apples = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			Apple apple = new Apple();
			apple.setWeigth(1);
			apple.setColor("");
			apples.add(apple);
		}

		Map<Integer, Apple> collect = apples.stream().collect(Collectors.toMap(Apple::getWeigth, Function.identity(),
				(existing, replacement) -> existing));
		System.out.println(collect);

	}

	@Test
	public void list2MapList() {
		System.out.println(appList);
		Map<String, List<Integer>> collect = appList.stream().collect(Collectors.groupingBy(
				Apple::getColor,
				Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().map(Apple::getWeigth).collect(Collectors.toList()))));
		System.out.println(collect);

		Map<String, List<Integer>> collect1 = appList.stream().collect(Collectors.groupingBy(
				Apple::getColor,
				Collectors.mapping(Apple::getWeigth, Collectors.toList())));
		System.out.println(collect1);

	}

	@Test
	public void toMapTest() {
		List<ToMapVO> list = new ArrayList<>();
		Map<Date, ToMapVO> collect = list.stream().collect(Collectors.toMap(ToMapVO::getAta, o -> o, (o1,o2) -> o2));

		Map<String, ToMapVO> collect1 =
				list.stream().collect(Collectors.toMap(a -> CollectGroupTest.trDate(a.getAta()), o -> o, (o1, o2) -> o2));

	}

	public static String trDate(Date date) {
		return "";
	}

	public static  class ToMapVO {
		private Date ata;

		public Date getAta() {
			return ata;
		}

		public void setAta(Date ata) {
			this.ata = ata;
		}
	}


	public static class GG {
		private String name;

		private String id;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getId() {
			return id;
		}

		public void setId(String id) {
			this.id = id;
		}
	}

	@Test
	public void groupByTest() {
		GG g1 = new GG();g1.setName("1");g1.setId("1");
		GG g2 = new GG();g2.setName("1");g2.setId("2");
		GG g3 = new GG();g3.setName("1");g3.setId("3");
		GG g4 = new GG();g4.setName("2");g4.setId("1");
		GG g5 = new GG();g5.setName("2");g5.setId("2");
		GG g6 = new GG();g6.setName("2");g6.setId("3");
		List<GG> ggList = new ArrayList<>();
		ggList.add(g1);
		ggList.add(g2);
		ggList.add(g3);
		ggList.add(g4);
		ggList.add(g5);
		ggList.add(g6);
		Map<String, List<GG>> collect = ggList.stream().collect(Collectors.groupingBy(g -> g.getId() + ";" + g.getName()));
		System.out.println(collect);
	}

	@Test
	public void testeee() {
		List<String> list = Arrays.asList("1", "1", "3", "2");
		List<String> existStr = new ArrayList<>();
		List<String> datas = new ArrayList<>();
		list.stream().forEach(s -> {
			if (existStr.contains(s)) {
				return;
			}
			existStr.add(s);
			datas.add(s);
		});
		System.out.println(datas);
	}

	@Test
	public void testsum() {
		List<Student> list = new ArrayList<>();
		Student s1 = new Student();s1.setName("a");s1.setAge(1);s1.setScore(new BigDecimal("1")); list.add(s1);
		Student s2 = new Student();s2.setName("a");s2.setAge(2);s2.setScore(new BigDecimal("2"));list.add(s2);
		Student s3 = new Student();s3.setName("b");s3.setAge(3);s3.setScore(new BigDecimal("3"));list.add(s3);
		Student s4 = new Student();s4.setName("c");s4.setAge(1);s4.setScore(new BigDecimal("1"));list.add(s4);

		//分组求数
		Map<String, Long> countMap =
				list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.counting()));
		System.out.println("countMap " + countMap);


		//分组求和
		Map<String, Integer> sum1 =
				list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.summingInt(Student::getAge)));
		System.out.println("sum1 " + sum1);

		Map<String, BigDecimal> sum4 =
				list.stream().collect(Collectors.groupingBy(Student::getName,
				Collectors.mapping(Student::getScore, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
		System.out.println("sum4 " + sum4);


		Map<String, Integer> sum2 =
				list.stream().collect(Collectors.toMap(Student::getName, Student::getAge, Integer::sum));
		System.out.println("sum2 " + sum2);


		Map<String, BigDecimal> sum31 =
				list.stream().collect(Collectors.toMap(s -> {return s.getName();}, s -> s.getScore() == null ? BigDecimal.ZERO : s.getScore(), BigDecimal::add));

		//推荐使用
		Map<String, BigDecimal> sum3 =
				list.stream().collect(Collectors.toMap(Student::getName, s -> s.getScore() == null ? BigDecimal.ZERO : s.getScore(), BigDecimal::add));
		System.out.println("sum3 " + sum3);

		List<Map<String, Object>> moreData = new ArrayList<>();
		Map<String, Object> map1 = new HashMap<>();
		map1.put("广告花费", 2);
		Map<String, Object> map2 = new HashMap<>();
		map2.put("广告花费", 20);
		Map<String, Object> map3 = new HashMap<>();
		map3.put("广告花费", 0.4);
		moreData.add(map1);
		moreData.add(map2);
		moreData.add(map3);
		BigDecimal transactionFee =
				moreData.stream().map(d -> new BigDecimal(Objects.toString(d.get("广告花费"), "0"))).reduce(BigDecimal.ZERO, BigDecimal::add);
		System.out.println(transactionFee);

	}

	@Test
	public void groupSortTest() {
		List<Student> list = new ArrayList<>();
		Student s1 = new Student();s1.setName("a");s1.setAge(1);s1.setScore(new BigDecimal("1")); list.add(s1);
		Student s4 = new Student();s4.setName("a");s4.setAge(4);s4.setScore(new BigDecimal("1"));list.add(s4);
		Student s2 = new Student();s2.setName("a");s2.setAge(2);s2.setScore(new BigDecimal("2"));list.add(s2);
		Student s3 = new Student();s3.setName("a");s3.setAge(3);s3.setScore(new BigDecimal("3"));list.add(s3);
		Map<String, List<Student>> collect = list.stream().collect(Collectors.groupingBy(Student::getName));
		System.out.println(JSON.toJSONString(collect, JSONWriter.Feature.PrettyFormat));

		System.out.println("========");

		Map<String, List<Student>> collect2 = list.stream().collect(Collectors.groupingBy(Student::getName, LinkedHashMap::new, Collectors.toList()));
		System.out.println(JSON.toJSONString(collect2, JSONWriter.Feature.PrettyFormat));

	}


	public static class Student {
		private String name;
		private Integer age;

		private BigDecimal score;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public Integer getAge() {
			return age;
		}

		public void setAge(Integer age) {
			this.age = age;
		}

		public BigDecimal getScore() {
			return score;
		}

		public void setScore(BigDecimal score) {
			this.score = score;
		}
	}


}
